/**
 * Copyright (C) 2011-2012 Rustam Bogubaev
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 */
package com.google.code.myminimvc.controller;

import com.google.code.myminimvc.Application;
import com.google.code.myminimvc.Controller;
import com.google.code.myminimvc.Requestable;
import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * Created by IntelliJ IDEA.
 * User: dev
 * Date: 8/30/11
 * Time: 12:30 AM
 */
public class ControllerInvocationHandler implements InvocationHandler {
    private final Logger logger = LoggerFactory.getLogger(ControllerInvocationHandler.class);

    Class<? extends Controller> clazz;
    private HttpServletRequest request;
    private HttpServletResponse response;

    private ControllerInvocationHandler() {
        // hide default constructor
    }

    public ControllerInvocationHandler(HttpServletRequest request, HttpServletResponse response, Class<? extends Controller> clazz) throws IllegalAccessException, InstantiationException {
        this.request = request;
        this.response = response;
        this.clazz = clazz;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Controller controller = clazz.newInstance();
        BeanUtils.populate(controller, request.getParameterMap());
        logger.debug("request converted to " + controller);

        attachToControllerRequest(controller);

        Object result = method.invoke(controller, args);

        attachModelToRequest(controller);

        return result;
    }

    /**
     * Attach controller model to the request attributes of which can be accessed
     * in jsp via ModelELResolver as ${model.attributeName}
     *
     * @param controller
     */
    private void attachModelToRequest(Controller controller) {
        request.setAttribute(Application.KEY_REQUEST_MODEL_HOLDER, controller);
    }

    private void attachToControllerRequest(Controller controller) {
        if (controller instanceof Requestable) {
            ((Requestable) controller).setRequest(request);
            logger.debug(controller.getClass() + " implements " + Requestable.class.getName() + ", so request was attached to the controller");
        }
    }

}
